home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / radio / radio.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  21KB  |  939 lines

  1. /***********************************************************
  2. Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
  3. Amsterdam, The Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI not be used in advertising or publicity pertaining to
  13. distribution of the software without specific, written prior permission.
  14.  
  15. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25. /* Receive audio UDP packets transmitted by broadcast.
  26.  
  27.    Command line options:
  28.  
  29.    -p port    tune to this port number (default 54321)
  30.                 (port numbers 1..99 are shorthands for 54321 and up)
  31.    -v volume    output volume (range 0-100; default unchanged)
  32.         (you can auso use [x_]gaintool or a similar tool to
  33.         set the output volume etc.)
  34.    -c port    use this control port (default 54320)
  35.    -s        'secure' mode: don't listen to the control port
  36.    -f        work as a filter: send output to stdout instead of
  37.         directly to the audio hardware
  38.    -l addr    listen only for packets to <arg> ip address
  39.    -r addr    listen only for packets from <arg>
  40.    -d        debug packets
  41.    -n           noninterruptable -- by default radio will be interruptable
  42.         by other sound outputting programs, hoping they do not
  43.         take too long.  This option turns off that feature.
  44.    -t        tee mode: send output to stdout as well as to audio h/w
  45.    -m mcastgrp    multicast group (SGI only)
  46. */
  47.  
  48. #include "radio.h"
  49. #include "patchlevel.h"
  50.  
  51. #include <stdio.h>
  52. #include <errno.h>
  53. #include <stdlib.h>
  54. #include <fcntl.h>
  55. #include <signal.h>
  56. #include <netdb.h>
  57. #include <sys/types.h>
  58. #include <sys/socket.h>
  59. #include <sys/time.h>
  60. #include <netinet/in.h>
  61.  
  62. #include "adpcm.h"
  63.  
  64. #ifdef HAVE_MCAST
  65. #include <arpa/inet.h>
  66.  
  67. #ifdef DEFMCAST
  68. char defmcast[] = DEFMCAST;
  69. #else
  70. char *defmcast = 0;
  71. #endif /* DEFMCAST */
  72.  
  73. #endif /* HAVE_MCAST */
  74.  
  75. #ifdef USE_AL
  76. #include <audio.h>
  77. #include "libst.h"
  78.  
  79. long savestate[] = {
  80.     AL_OUTPUT_RATE, 0,
  81.     /* The following two must be the last pairs! */
  82.     AL_LEFT_SPEAKER_GAIN, 0,
  83.     AL_RIGHT_SPEAKER_GAIN, 0,
  84. };
  85.  
  86. ALport aport;
  87.  
  88. void cleanup_handler();
  89. #endif /* USE_AL */
  90.  
  91. #ifdef USE_SUN
  92. #include <stropts.h>
  93. #include <sun/audioio.h>
  94.  
  95. #define AUDIO_IODEV     "/dev/audio"
  96. #define AUDIO_CTLDEV    "/dev/audioctl"
  97.  
  98. int interruptable = 1;
  99. int actlfd = -1;
  100. int afd = -1;
  101.  
  102. void sigpoll_handler();
  103. #endif /* USE_SUN */
  104.   
  105. #ifdef USE_NX
  106. #include <sound/sound.h>
  107. #define NUM_BUFFER 10
  108. SNDSoundStruct *snd[NUM_BUFFER];
  109. #endif /* USE_NX */
  110.  
  111. #ifdef USE_LOFI
  112.  
  113. #include "lofi.h"
  114. #include "lofiMap.h"
  115. #include "codec.h"
  116. #include "ringbuffers.h"
  117. #include "libst.h"
  118.  
  119. #define DEVLOFI "/dev/lofi"
  120.  
  121. #endif /* USE_LOFI */
  122.  
  123. #ifdef USE_AF
  124.  
  125. #include <AF/AFlib.h>
  126. #include <math.h>
  127.  
  128. int device;
  129.  
  130. AFAudioConn *aud;
  131. AC audio_context;
  132. AFSetACAttributes attributes;
  133.  
  134. #endif /* USE_AF */
  135.  
  136. #ifdef CHECK_X_SERVER
  137. #include <X11/Xlib.h>
  138. Display *xdisplay = 0;
  139. #endif /* CHECK_X_SERVER */
  140.  
  141. /* getopt() interface */
  142. extern int optind;
  143. extern char * optarg;
  144.  
  145. /* Globals */
  146. int pausing = 0; /* Flag set when pausing */
  147. int ofd = -1; /* Output file descriptor */
  148. int volume = -1; /* -v parameter */
  149. int pdebug = 0; /* -p parameter */
  150. char *mcastgrp = 0; /* -m parameter */
  151.  
  152. #ifdef USE_LOFI
  153. struct lofiPhysDevice *outdev;
  154. #endif /* USE_LOFI */
  155.  
  156. /* Forward functions */
  157. void open_speaker();
  158. void close_speaker();
  159. void checkalive();
  160. void setmcast(); /* Forward */
  161.  
  162. main(argc, argv)
  163.     int argc;
  164.     char **argv;
  165. {
  166.     int receiveport = RCVPORT;
  167.     int ctlport = RADIOCTLPORT;
  168.     char real_buf[BUFFERSIZE + HEADERSIZE];
  169.     char tmp_buf[BUFFERSIZE];
  170.     int encoding;
  171.     char *buf;
  172.     int s, ctls, curs;
  173.     struct sockaddr from;
  174.     int fromlen;
  175.     int c;
  176.     int filter = 0;
  177.     int tee = 0;
  178.     int nfds;
  179.     fd_set inputset;
  180.     int n;
  181.     char *localname = (char *) NULL;
  182.     char *remotename = (char *) NULL;
  183.     struct timeval timeout;
  184.     int packetcount;
  185.     struct adpcm_state state;
  186. #ifdef USE_AL
  187.     short obuf[BUFFERSIZE];
  188.     int i;
  189.     int curdatalinear;
  190. #endif
  191. #ifdef USE_NX
  192.     int akt_buf;
  193. #endif
  194. #ifdef USE_LOFI
  195.     DSPTime ptime;
  196.     int first_time = 1, status = FALSE;
  197.     int i;
  198.     char *np, *p;
  199.     short obuf[BUFFERSIZE];
  200. #endif
  201. #ifdef USE_AF
  202.     extern int device;
  203.     extern AC audio_context;
  204.     extern AFSetACAttributes attributes;
  205. #endif /* USE_AF */
  206.  
  207. /* Always change these two macros and the following switch together! */
  208. #define OPTIONS "c:dfl:m:np:r:stv:"
  209. #define USAGE "usage: %s [options]\n\
  210. User options:\n\
  211. -p port      : port to listen to (default 54321; 1..99 ==> 54321..54419)\n\
  212. -v volume    : volume setting (1-100; default unchanged)\n\
  213. Expert options:\n\
  214. -f           : filter mode (write data to stdout)\n\
  215. -t           : tee mode (write data to stdout as well as to audio device)\n\
  216. -n           : not interruptable by other sources (Sun only)\n\
  217. -c ctlport   : control port for tuner programs (default 54320)\n\
  218. -s           : secure mode: no control port (disallow tuner programs)\n\
  219. Guru options:\n\
  220. -l localhost : listen to packets to this host only\n\
  221. -r remothost : receive packets from that host only\n\
  222. -m mcastgrp  : multicast group (not always supported)\n\
  223. -d           : debugging mode (writes messages to stderr)\n\
  224. "
  225.  
  226.     while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
  227.         switch (c) {
  228.         case '?':
  229.             fprintf(stderr, USAGE, argv[0]);
  230.             exit(2);
  231.         case 'p':
  232.             receiveport = atoi(optarg);
  233.             if (0 < receiveport && receiveport < 100)
  234.                 receiveport += RCVPORT-1;
  235.             break;
  236.         case 'c':
  237.             ctlport = atoi(optarg);
  238.             break;
  239.         case 'l':
  240.             localname = optarg;
  241.             break;
  242.         case 'r':
  243.             remotename = optarg;
  244.             break;
  245.         case 'd':
  246.             pdebug = 1;
  247.             break;
  248.         case 'm':
  249. #ifdef HAVE_MCAST
  250.             mcastgrp = optarg;
  251. #else
  252.             fprintf(stderr, "(-m not supported here)\n");
  253. #endif
  254.             break;
  255.         case 'n':
  256. #ifdef USE_SUN
  257.             interruptable = 0;
  258. #else
  259.             fprintf(stderr, "(-n not supported here)\n");
  260. #endif
  261.             break;
  262.         case 's':
  263.             ctlport = -1;
  264.             break;
  265.         case 'f':
  266.             filter = 1;
  267.             tee = 0;
  268.             break;
  269.         case 't':
  270.             tee = 1;
  271.             filter = 0;
  272.             break;
  273.         case 'v':
  274.             volume = atoi(optarg);
  275.             break;
  276.         }
  277.     }
  278.  
  279.     /* Meaning of the 'tee' and 'filter' flags:
  280.        At most one of these can be on.
  281.        if tee is on: write stdout and "/dev/audio";
  282.        if filter is on: write stdout only;
  283.        if both are off: write "/dev/audio" only;
  284.        where "/dev/audio" stands for whatever audio hardware we have. */
  285.  
  286.     if (filter || tee)
  287.         ofd = fileno(stdout);
  288.     if (!filter) {
  289.         open_speaker();
  290. #ifdef CHECK_X_SERVER
  291.         xdisplay = XOpenDisplay((char *)NULL);
  292.         if (xdisplay == NULL) {
  293.             fprintf(stderr,
  294. "radio: warning: no X server -- you must kill radio when you log out!\n");
  295.         }
  296. #endif
  297.     }
  298.  
  299.     if (ctlport >= 0)
  300.         ctls = opensock("control", (char *)NULL, ctlport,
  301.                 (char *)NULL, 0, 0);
  302.     else
  303.         ctls = -1;
  304.  
  305.     s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
  306. #ifdef HAVE_MCAST
  307.     if (mcastgrp)
  308.         setmcast(s, mcastgrp);
  309.     else if (defmcast)
  310.         setmcast(s, defmcast);
  311. #endif
  312.  
  313.     packetcount = 0;
  314.  
  315.     for (;;) {
  316.         /*
  317.         ** Wait until one of the sockets becomes ready
  318.         */
  319.         for (;;) {
  320.             nfds = (s > ctls ? s : ctls) + 1;
  321.             FD_ZERO(&inputset);
  322.             FD_SET(s, &inputset);
  323.             if (ctls >= 0)
  324.                 FD_SET(ctls, &inputset);
  325.             timeout.tv_sec = 30;
  326.             timeout.tv_usec = 0;
  327.             n = select(nfds, &inputset, 0, 0, &timeout);
  328.             if (n > 0)
  329.                 break;
  330.             if (n == 0) {
  331.                 checkalive();
  332.             }
  333.             else if (errno != EINTR) {
  334.                 perror("select");
  335.                 exit(1);
  336.             }
  337.         }
  338.         if (ctls >= 0 && FD_ISSET(ctls, &inputset))
  339.             curs = ctls;
  340.         else if (FD_ISSET(s, &inputset))
  341.             curs = s;
  342.         /*
  343.         ** Read, and check for control packet
  344.         */
  345.         fromlen = sizeof(from);
  346.         buf = real_buf;
  347.         n = recvfrom(curs, buf, HEADERSIZE + BUFFERSIZE, 0,
  348.                  &from, &fromlen);
  349.         if (n <= 0) {
  350.             if (n == 0)
  351.                 continue; /* Ignore empty packets */
  352.             perror("read");
  353.             break;
  354.         }
  355.         if (pdebug) {
  356.             if(pdebug == 8) {
  357.                 fprintf(stderr, "8 packets received\n");
  358.                 pdebug = 1;
  359.             }
  360.             else
  361.                 pdebug++;
  362.         }
  363.         if (n <= CTLPKTSIZE) {
  364.             /*
  365.             ** It looks like a control packet. Check it.
  366.             */
  367.             buf[n] = '\0';
  368.             if (strncmp(buf, "radio:", 6) == 0) {
  369.                 if (pdebug)
  370.                     fprintf(stderr, "control packet\n");
  371.                 switch(buf[6]) {
  372.                 case 'e':        /* Echo */
  373.                     buf[6] = 'E';
  374.                     sendto(curs, buf, n, 0,
  375.                            &from, fromlen);
  376.                     break;
  377.                 case 'S':    /* Status from broadcast */
  378.                     if (pdebug)
  379.                         fprintf(stderr,
  380.                             "Status %s\n", buf);
  381.                     break;
  382.                 case 't':        /* Tune */
  383.                     if (curs != ctls) {
  384.                         if (pdebug)
  385.                           fprintf(stderr,
  386.                             "radio: illegal tune\n");
  387.                         break;
  388.                     }
  389. #ifdef USE_SUN
  390.                     if (!filter) {
  391.                         (void) ioctl(ofd, I_FLUSH,
  392.                                  FLUSHW);
  393.                     }
  394. #endif /* USE_SUN */
  395.                     receiveport = atoi(buf+8);
  396.                     close(s);
  397.                     s = opensock("new data", localname,
  398.                              receiveport, remotename,
  399.                              SENDPORT, 0);
  400. #ifdef HAVE_MCAST
  401.                     if (mcastgrp)
  402.                         setmcast(s, mcastgrp);
  403.                     else if (defmcast)
  404.                         setmcast(s, defmcast);
  405. #endif
  406.                     break;
  407.                 case 'i':        /* Info */
  408.                     sprintf(buf, "radio:I:%d:%d:%s.%d",
  409.                         !pausing, receiveport,
  410.                         VERSION, PATCHLEVEL);
  411.                     sendto(curs, buf, strlen(buf), 0,
  412.                            &from, fromlen);
  413.                     break;
  414. #ifndef USE_NX /* XXX I don't know how to close_speaker() on the NeXT */
  415.                 case 'p':        /* Pause */
  416.                 case '0': /* Backward compatibility */
  417.                     if (!filter && !pausing) {
  418.                         close_speaker();
  419.                         pausing = 1;
  420.                     }
  421.                     break;
  422.                 case 'c':        /* Continue */
  423.                 case '1': /* Backward compatibility */
  424.                     if (pausing) {
  425.                         open_speaker();
  426.                         pausing = 0;
  427.                     }
  428.                     break;
  429. #endif /* USE_NX */
  430.                 default:
  431.                     if (pdebug)
  432.                         fprintf(stderr,
  433.                           "radio: illegal cmd '%c'\n",
  434.                           buf[6]);
  435.                 }
  436.             }
  437.             else if (pdebug) {
  438.                 fprintf(stderr,
  439.                     "radio: ill-formatted command\n");
  440.             }
  441.         }
  442.         else if (!pausing) {
  443.             encoding = PCM_64;
  444. #ifdef USE_AL
  445.             curdatalinear = 0;
  446. #endif /* USE_AL */            
  447.             if ((buf[0]&0xff) == AUDIO_TYPE) {
  448.                 encoding = buf[1]&0xff;
  449.                 buf += HEADERSIZE;
  450.                 n -= HEADERSIZE;
  451.             }
  452.             else {
  453.                 if (pdebug)
  454.                     fprintf(stderr,
  455.                         "radio: non-IVS packet\n");
  456.                 continue;
  457.             }
  458.             switch (encoding) {
  459.  
  460.             case PCM_64:
  461.                 break;
  462.  
  463.             case ADPCM_32:
  464.                 n = n*2;
  465. #ifdef USE_AL
  466.                 /*
  467.                 ** For SGI and non-filter mode, don't convert
  468.                 ** via ulaw but straight to linear
  469.                 */
  470.                 if (!filter) {
  471.                     curdatalinear = 1;
  472.                     adpcm_decoder(buf, obuf, n,
  473.                               (struct adpcm_state *)0);
  474.                 }
  475.                 else
  476. #endif /* USE_AL */
  477.                 {
  478.                     adpcm_ulaw_decoder(buf, tmp_buf, n,
  479.                            (struct adpcm_state *)0);
  480.                     buf = tmp_buf;
  481.                 }
  482.                 break;
  483.  
  484.             case ADPCM_32_W_STATE:
  485.                 state.valprev =
  486.                     ((buf[0]&0xff)<<8) | (buf[1]&0xff);
  487.                 state.index = buf[2]&0xff;
  488.                 buf += 3;
  489.                 n -= 3;
  490.                 n = n*2;
  491. #ifdef USE_AL                
  492.                 if (!filter) {
  493.                     adpcm_decoder(buf, obuf, n, &state);
  494.                     curdatalinear = 1;
  495.                 }
  496.                 else
  497. #endif /* USE_AL */
  498.                 {
  499.                     adpcm_ulaw_decoder(buf, tmp_buf, n,
  500.                                &state);
  501.                     buf = tmp_buf;
  502.                 }
  503.                 break;
  504.  
  505.             default:
  506.                 if (pdebug)
  507.                     fprintf(stderr,
  508.                         "radio: unknown encoding %d\n",
  509.                         encoding);
  510.                 /* Ignore the package */
  511.                 continue;
  512.  
  513.             }
  514. #ifdef USE_AL
  515.             if (!filter) {
  516.                     if (!curdatalinear)
  517.                     for (i = 0; i < n; i++)
  518.                         obuf[i] =
  519.                         st_ulaw_to_linear(buf[i]&0xff);
  520.                 ALwritesamps(aport, obuf, (long)n);
  521.             }
  522. #endif /* USE_AL */
  523. #ifdef USE_NX
  524.             if (!filter) {
  525.                 int dummy;
  526.                 char *ptr;
  527.                 
  528.                 (void) SNDGetDataPointer(snd[akt_buf], &ptr,
  529.                              &dummy, &dummy);
  530.                 
  531.                 SNDWait(akt_buf+1);
  532.                 memcpy(ptr, buf, n);
  533.                 snd[akt_buf] -> dataSize = n;
  534.                 SNDStartPlaying(snd[akt_buf],
  535.                         akt_buf+1, 5, 0, 0, 0);
  536.                 akt_buf = (akt_buf + 1) % NUM_BUFFER;
  537.             }
  538. #endif /* USE_NX */
  539. #ifdef USE_SUN
  540.             if (!filter) {
  541.                 if (write(afd, buf, n) != n) {
  542.                     perror("write afd");
  543.                     break;
  544.                 }
  545.             }
  546. #endif /* USE_SUN */
  547. #ifdef USE_LOFI 
  548.             if(!filter) 
  549.                 lofiWriteNow(outdev, buf, n, CODEC_SECONDARY);
  550. #endif /* USE_LOFI */
  551. #ifdef USE_AF
  552.             if(!filter)
  553.             {
  554.                 static ATime next_time;
  555.                 ATime now;
  556.                 int dt;
  557.                 if (next_time == 0)
  558.                     next_time = AFGetTime(audio_context)
  559.                             + 8000;
  560.                 now = AFPlaySamples(audio_context,
  561.                             next_time, n, buf);
  562.                 next_time += n;
  563.                 dt = next_time - now;
  564.                 /* If next_time is not within 4000-12000
  565.                    samples in the future, adapt it.
  566.                    The current packet may be lost,
  567.                    but at least the next one will be
  568.                    alright, and we have saved a server
  569.                    round trip. */
  570.                 if (dt < 4000 || dt > 12000) {
  571.                     if (pdebug)
  572.                         fprintf(stderr,
  573.                             "Adapting (%d)\n", dt);
  574.                     next_time = now+8000;
  575.                 }
  576.             }
  577. #endif /* USE_AF */
  578.             if (filter || tee) {
  579.                 if (write(ofd, buf, n) != n) {
  580.                     perror("write ofd");
  581.                     break;
  582.                 }
  583.             }
  584.         }
  585.         if (++packetcount > (30*SAMPLINGRATE / BUFFERSIZE)) {
  586.             checkalive();
  587.             packetcount = 0;
  588.         }
  589.     }
  590.  
  591.     exit(0);
  592. }
  593.  
  594. #ifdef USE_AL
  595.  
  596. void open_speaker()
  597. {
  598.     ALconfig config;
  599.     long pvbuf[6];
  600.     
  601.     /* Fetch the original state */
  602.     ALgetparams(AL_DEFAULT_DEVICE, savestate,
  603.             sizeof(savestate) / sizeof(long));
  604.     
  605.     /* Set signal handlers */
  606.     signal(SIGINT, cleanup_handler);
  607.     signal(SIGTERM, cleanup_handler);
  608.     
  609.     /* Set the output sampling rate */
  610.     pvbuf[0] = AL_OUTPUT_RATE;
  611.     pvbuf[1] = SAMPLINGRATE; /* XXX Assume AL_RATE_n is n */
  612.     
  613.     /* Maybe also set the volume */
  614.     if (volume >= 0) {
  615.         pvbuf[2] = AL_LEFT_SPEAKER_GAIN;
  616.         pvbuf[3] = volume*255/100;
  617.         pvbuf[4] = AL_RIGHT_SPEAKER_GAIN;
  618.         pvbuf[5] = volume*255/100;
  619.         ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 6L);
  620.     }
  621.     else
  622.         ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
  623.     
  624.     /* Configure and open an SGI audio port */
  625.     config = ALnewconfig();
  626.     ALsetchannels(config, AL_MONO);
  627.     ALsetwidth(config, AL_SAMPLE_16);
  628.     ALsetqueuesize(config, 16000); /* 2 seconds slop */
  629.     aport = ALopenport("radio", "w", config);
  630.     if (aport == NULL) {
  631.         perror("ALopenport");
  632.         exit(1);
  633.     }
  634. }
  635.  
  636. void close_speaker()
  637. {
  638.     ALcloseport(aport);
  639.     aport = NULL;
  640. }
  641.  
  642. void cleanup_handler(sig)
  643.     int sig;
  644. {
  645.     signal(sig, SIG_DFL);
  646.     if (!pausing) {/* Don't reset anything if we're pausing */
  647.         long n = sizeof(savestate) / sizeof(long);
  648.         if (volume < 0)
  649.             n -= 4; /* Don't reset volume if we didn't set it */
  650.         ALsetparams(AL_DEFAULT_DEVICE, savestate, n);
  651.     }
  652.     kill(getpid(), sig);
  653. }
  654.  
  655. #endif /* USE_AL */
  656.  
  657.  
  658. #ifdef USE_SUN
  659.  
  660. void open_speaker()
  661. {    
  662.     audio_info_t info;
  663.  
  664.     /* Write to AUDIO_IODEV */
  665.     if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  666.         perror(AUDIO_IODEV);
  667.         exit(1);
  668.     }
  669.  
  670.     /* Set the volume */
  671.     if (volume >= 0) {
  672.         AUDIO_INITINFO(&info);
  673.         info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
  674.         if (ioctl(afd, AUDIO_SETINFO, &info))
  675.             perror("volume setting");
  676.     }
  677.  
  678.     /* We need to open the audio control port to detect
  679.        if someone else wants to output to /dev/audio.
  680.        If this fails (e.g., in SunOS 4.0), print a message
  681.        but don't exit. */
  682.     if (interruptable) {
  683.         if ((actlfd = open(AUDIO_CTLDEV, O_RDWR)) < 0) {
  684.             perror(AUDIO_CTLDEV);
  685.         }
  686.         else if (ioctl(actlfd, I_SETSIG, S_MSG) < 0) {
  687.             perror("I_SETSIG");
  688.         }
  689.         else if (signal(SIGPOLL, sigpoll_handler) < 0) {
  690.             perror("signal(SIGPOLL)");
  691.             exit(1);
  692.         }
  693.     }
  694. }
  695.  
  696. void close_speaker()
  697. {
  698.     (void) ioctl(afd, I_FLUSH, FLUSHW);
  699.     close(afd);
  700.     close(actlfd);
  701.     afd = actlfd = -1;
  702. }
  703.  
  704. void sigpoll_handler()
  705. {
  706.     audio_info_t ap;
  707.  
  708.     if (ioctl(actlfd, AUDIO_GETINFO, &ap) < 0) {
  709.         perror("AUDIO_GETINFO");
  710.     }
  711.     else if (ap.play.waiting) {
  712.         (void) ioctl(afd, I_FLUSH, FLUSHW);
  713.         close(afd);
  714.         /* The open() call blocks until we can use the device again */
  715.         if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  716.             perror(AUDIO_IODEV);
  717.             exit(1);
  718.         }
  719.         ap.play.waiting = 0;
  720.         if (ioctl(actlfd, AUDIO_SETINFO, &ap) < 0) {
  721.             perror("AUDIO_SETINFO");
  722.         }
  723.     }
  724. }
  725.  
  726. #endif /* USE_SUN */
  727.  
  728.  
  729. #ifdef USE_NX
  730.  
  731. void open_speaker()
  732. {
  733.     int akt_buf;
  734.     int err;
  735.  
  736.     /* Alloc NUM_BUFFER Sounds */
  737.     for (akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) {
  738.         if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE,
  739.                    SND_FORMAT_MULAW_8,
  740.                    SND_RATE_CODEC, 1, 4)) {
  741.             fprintf(stderr, "init: %s\n", SNDSoundError(err));
  742.             exit(1);
  743.         }
  744.     }
  745.     akt_buf = 0;
  746. }
  747.  
  748. void close_speaker()
  749. {
  750.     /* XXX how to do this? */
  751. }
  752.  
  753. #endif /* USE_NX */
  754.  
  755. #ifdef USE_LOFI
  756. void open_speaker()
  757. {
  758.     int status;
  759.     extern struct lofiPhysDevice *outdev;
  760.     
  761.     /* Open the devlofi device */
  762.     
  763.     outdev = lofiOpen(DEVLOFI);
  764.     if(outdev == NULL)
  765.     {
  766.     fprintf(stderr, "Could not open lofi %s\n", DEVLOFI);
  767.     exit(1);
  768.     }
  769.     
  770.     /* Set up the lofi hardware for playing from the internal
  771.        speaker. */
  772.     
  773.     status = lofiHWInit(outdev, 
  774.             NULL, /* let it find it's own lod file */
  775.             0, /* Primary codec output */
  776.             CODEC_SPEAKER, /* Secondary codec output */
  777.             0, /* Primary codec input */
  778.             0, /* Secondary codec input */
  779.             FALSE);
  780.     
  781.     if(volume >0)
  782.     lofiSetOutputVolume(outdev, CODEC_SPEAKER, volume / 10);
  783.  
  784.     if(status == FALSE)
  785.     {
  786.     fprintf(stderr,"Could not init the hardware,is AUDIO_ROOT set?\n");
  787.     lofiClose(outdev);
  788.     exit(1);
  789.     }
  790.  
  791. }    
  792.  
  793. void close_speaker()
  794. {
  795.     extern struct lofiPhysDevice *outdev;
  796.     lofiClose(outdev);
  797.     
  798. }
  799.  
  800. #endif /* USE_LOFI */
  801.  
  802. #ifdef USE_AF
  803. void open_speaker()
  804. {
  805.  
  806.     int outcur, outmin, outmax, steps;
  807.  
  808.     extern int device;
  809.  
  810.     extern AFAudioConn *aud;
  811.     extern AC audio_context;
  812.     extern AFSetACAttributes attributes;
  813.  
  814.     if((aud = AFOpenAudioConn("")) == NULL) 
  815.     {
  816.     fprintf(stderr, "radio: can't open connection.\n");
  817.     exit(1);
  818.     }
  819.     
  820.     /* set up audio context, find sample size and sample rate */
  821.     
  822.     device = FindDefaultDevice(aud);
  823.  
  824.     if(device < 0)
  825.     {
  826.     fprintf(stderr, "radio: unable find a suitable device.\n");
  827.     exit(1);
  828.     }
  829.     
  830.     attributes.preempt = Mix;
  831.     attributes.start_timeout = 0;
  832.     attributes.end_silence = 0;
  833.     attributes.rec_gain =  0;
  834.     
  835.     audio_context = AFCreateAC(aud, device, ACPlayGain, &attributes);
  836.  
  837.     outcur = AFQueryOutputGain(audio_context, &outmin, &outmax);
  838.     
  839.     if(volume == 0)
  840.     AFSetOutputGain(audio_context, outmin);
  841.     else
  842.     if(volume > 0)
  843.     {
  844.         steps = outmax - outmin;
  845.         AFSetOutputGain(audio_context, outmin + (steps * volume /100));
  846.     } 
  847.     else
  848.         AFSetOutputGain(audio_context, 0);
  849.  
  850. }    
  851.  
  852. void close_speaker()
  853. {
  854.     extern AFAudioConn *aud;
  855.     extern AC audio_context;
  856.  
  857.     AFFreeAC(audio_context);
  858.     AFCloseAudioConn(aud);
  859. }
  860.  
  861. #endif /* USE_LOFI */
  862.  
  863. void checkalive()
  864. {
  865. #ifdef CHECK_X_SERVER
  866.     if (xdisplay) {
  867.         Window focus;
  868.         int revert_to;
  869.         if (pdebug)
  870.             fprintf(stderr, "polling X server...\n");
  871.         /* Do a simple X request that needs a server round trip...
  872.            The error handler will kill us when the server is dead,
  873.            so that radio dies when the user logs out. */
  874.         XGetInputFocus(xdisplay, &focus, &revert_to);
  875.         if (pdebug)
  876.             fprintf(stderr, "X server OK\n");
  877.     }
  878.     else if (pdebug)
  879.         fprintf(stderr, "checkalive() is a no-op\n");
  880. #endif /* CHECK_X_SERVER */
  881. }
  882.  
  883. void setmcast(s, group)
  884.     int s;
  885.     char *group;
  886. {
  887. #ifdef HAVE_MCAST
  888.     struct hostent *hostentry;
  889.     struct in_addr grpaddr;
  890.     struct in_addr ifaddr;
  891.     struct ip_mreq mreq;
  892.  
  893.     if (hostentry = gethostbyname(group))
  894.     {
  895.         bcopy(hostentry->h_addr, &grpaddr.s_addr, sizeof(grpaddr.s_addr));
  896.     }
  897.     else
  898.         grpaddr.s_addr = inet_addr(group);
  899.  
  900.     if (!IN_MULTICAST(grpaddr.s_addr)) {
  901.         fprintf(stderr, "Bad multicast group: %s\n", group);
  902.         exit(1);
  903.     }
  904.     
  905.     ifaddr.s_addr = htonl(INADDR_ANY);
  906.     
  907.     mreq.imr_multiaddr = grpaddr;
  908.     mreq.imr_interface = ifaddr;
  909.     if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  910.                &mreq, sizeof(mreq)) < 0) {
  911.         perror("setsockopt mreq");
  912.         exit(1);
  913.     }
  914. #endif /* HAVE_MCAST */
  915. }
  916.  
  917. #ifdef USE_AF
  918.  
  919. /* This routine searches for a suitable device to play 8kHz uLaw 
  920.    encoded audio on. */
  921.  
  922. int FindDefaultDevice(aud)             
  923. AFAudioConn *aud; 
  924. {
  925.         AFDeviceDescriptor *aDev;
  926.         int     i;
  927.  
  928.         for(i=0; i<ANumberOfAudioDevices(aud); i++) {
  929.                 aDev = AAudioDeviceDescriptor(aud, i);
  930.                 if(aDev->inputsFromPhone == 0 && 
  931.            aDev->outputsToPhone == 0 &&
  932.            aDev->playSampleFreq == 8000 &&
  933.            aDev->playBufType == MU255)
  934.             return i;
  935.         }
  936.         return -1;
  937. }
  938. #endif /* USE_AF */
  939.